<?php

declare(strict_types=1);

namespace app\common\Logic;

use app\common\ApiClient;
use app\common\RedisClient;
use think\facade\Db;
use app\admin\common\ServiceResponse;
use think\facade\Log;

class DingTalk
{

    use ServiceResponse;

    protected $env;
    protected $newDomain;
    protected $oldDomain;
    protected $appKey;
    protected $appSecret;
    protected $agentId;
    protected $robotCode;
    protected $headers;

    public function __construct()
    {
        $this->env = env('APP_ENV') ?? 'prod';
        $this->newDomain = config('domain')[$this->env]['newDingtalk'];
        $this->oldDomain = config('domain')[$this->env]['oldDingtalk'];

        $this->appKey = env('DINGTALK_APPKEY');
        $this->appSecret = env('DINGTALK_APPSECRET');
        $this->agentId = env('DINGTALK_AGENTID');
        $this->robotCode = env('DINGTALK_ROBOTCODE');
        $this->headers = [
            'Content-Type' => 'application/json',
            'x-acs-dingtalk-access-token' => $this->getAccessToken('new'),
        ];
    }







    /**
     * @describe 发送工作通知
     * document: https://open.dingtalk.com/document/isvapp/send-job-notification
     * @author: Bobo
     * @date: 2025-01-09 15:48:54 
     * @param $operatorIDList  [arr] @required [ERP用户ID] 
     * @param $departmentIDList [arr] @required [ERP部门ID]
     * @param $type [str] @required [消息类型] text|image|voice|file|link|oa|markdown|action_card
     * 
     * 
     * @return Renderable
     */
    // 发送工作通知消息
    public function SendJobNotificationMessage(array $message, array $operatorIDList, $departmentIDList = [])
    {

        $operatorIDList = array_unique($operatorIDList);
        // 根据operatorIDList查询operator表，获取operatorList
        $operatorList = Db::name('operator')->whereIn('id', $operatorIDList)->column('id,unionId,userid');
        // 如果查询结果数量不等于operatorIDList数量，说明部分用户不存在
        if (count($operatorList) !== count($operatorIDList)) {
            return [
                'result' => false,
                'msg' => '部分用户不存在'
            ];
        }
        $dingTalkUserIDStr = '';

        // 遍历operatorList，获取每个operator的dingTalkUserID
        foreach ($operatorList as $operator) {
            $operatorDingTalkUserID = '';
            // 如果operator的userid存在，则使用userid
            if ($operator['userid']) {
                $operatorDingTalkUserID = $operator['userid'];
            } else {
                if ($operator['unionId']) {
                    // 如果operator的userid不存在，则根据unionId获取dingTalkUserID
                    $operatorDingTalkUserID = $this->getDingTalkUserIDWithUnionId($operator['unionId']);
                    // 更新operator表的userid字段
                    Db::name('operator')->where('id', $operator['id'])->update(['userid' => $operatorDingTalkUserID]);
                } else {
                    Log::error('钉钉通知发送失败: operator的unionId不存在: ' . $operator['id']);
                }
            }
            // 将dingTalkUserID添加到dingTalkUserIDStr中
            $dingTalkUserIDStr .= $operatorDingTalkUserID . ',';
        }

        $accessToken = $this->getAccessToken('new');
        if (empty($accessToken)) {
            return [
                'result' => false,
                'msg' => '获取access_token失败'
            ];
        }
        // 获取access_token
        $path =   '/topapi/message/corpconversation/asyncsend_v2?access_token=' . $accessToken;

        // 构造请求体
        $body = [
            "msg" => $message,
            "to_all_user" => "false",
            "agent_id" => $this->agentId,
            // "dept_id_list" => "123,456", // 部门
            "userid_list" => $dingTalkUserIDStr
        ];
        // 创建ApiClient实例
        $apiClient = new ApiClient($this->oldDomain);

        try {
            // 发送请求
            $response = $apiClient->post(
                $path,
                [
                    'body' => json_encode($body)
                ]
            );
            // 如果errcode为0，说明发送成功
            if (0 == $response['errcode']) {
                return [
                    'result' => true,
                    'msg' => '发送成功'
                ];
            } else {
                // 否则，返回错误信息
                return [
                    'result' => false,
                    'msg' => $response['errmsg']
                ];
            }
        } catch (\Throwable $th) {
            // 捕获异常，返回错误信息
            return [
                'result' => false,
                'msg' => $th->getMessage()
            ];
        }
    }






    /**
     * @describe 发送群聊消息
     * document https://open.dingtalk.com/document/orgapp/the-robot-sends-a-group-message
     * @author: Bobo
     * @date: 2025-01-15 13:41:36 
     * @param $msgParam [string] @required  消息内容
     * @param $msgKey [string] @required  消息类型
     * @param $openConversationId [string] @required  群聊会话ID
     * @param $robotCode [string] @required  机器人code
     * @return Renderable
     */
    public function SendGroupChatMessage(string $msgParam, string  $msgKey, string $openConversationId)
    {
        // 获取access_token
        $path =   '/v1.0/robot/groupMessages/send';

        // 构造请求体
        $body = [
            "msgParam" => $msgParam,
            "msgKey" => $msgKey,
            "openConversationId" => $openConversationId,
            "robotCode" => $this->robotCode,
        ];
        // 创建ApiClient实例
        $apiClient = new ApiClient($this->newDomain);

        try {
            // 发送请求
            $response = $apiClient->post(
                $path,
                [
                    'body' => json_encode($body),
                    'headers' => $this->headers
                ]
            );
            // 如果$response['processQueryKey'] 存在，说明发送成功
            if (isset($response['processQueryKey'])) {
                return [
                    'result' => true,
                    'msg' => '发送成功'
                ];
            } else {
                // 否则，返回错误信息
                return [
                    'result' => false,
                    'msg' => $response['message']
                ];
            }
        } catch (\Throwable $th) {
            // 捕获异常，返回错误信息
            return [
                'result' => false,
                'msg' => $th->getMessage()
            ];
        }
    }
    /**
     * @describe
     * @author: Bobo
     * @date: 2025-01-09 16:07:20 
     * @param [type] @required
     * @return Renderable
     */
    public function getAccessToken(string $version)
    {
        $redisClient = new RedisClient();
        $accessToken = $redisClient->get($version . '_dingtalk_access_token');

        if ($accessToken) {
            return $accessToken;
        } else {
            if ('new' == $version) {
                $url =  $this->newDomain . '/v1.0/oauth2/accessToken';
                $option =                 [
                    'body' => json_encode([
                        'appKey' => $this->appKey,
                        'appSecret' => $this->appSecret,
                    ])
                ];

                $apiClient = new ApiClient($url);
                $response = $apiClient->post(
                    '/',
                    $option
                );
                if (isset($response['expireIn'], $response['accessToken'])) {
                    $redisClient->set($version . '_dingtalk_access_token', $response['accessToken']);
                    $redisClient->setExpiry($version . '_dingtalk_access_token', $response['expireIn'] - 60);
                    return $response['accessToken'];
                };
            } else {
                $url = $this->oldDomain;
                $option = [];
                $apiClient = new ApiClient($url);
                $response = $apiClient->get('gettoken?appkey=' . $this->appKey . '&appsecret=' . $this->appSecret);
                if (isset($response['expireIn'], $response['accessToken'])) {
                    $redisClient->set($version . '_dingtalk_access_token', $response['access_token']);
                    $redisClient->setExpiry($version . '_dingtalk_access_token', $response['expires_in'] - 60);
                    return $response['access_token'];
                };
            }
        }
    }

    /**
     * @describe shi
     * @author: Bobo
     * @date: 2025-01-10 14:57:20 
     * @param [type] @required
     * @return Renderable
     */
    public function getDingTalkUserIDWithUnionId(string $unionId)
    {

        $domian = $this->oldDomain;
        $accessToken = $this->getAccessToken('new');
        if (!$accessToken) {
            return false;
        }
        $path = 'topapi/user/getbyunionid?access_token=' . $accessToken;

        $apiClient = new ApiClient($domian);
        $body = [
            'unionid' => $unionId
        ];
        $response = $apiClient->post(
            $path,
            ['body' => json_encode($body)]
        );
        if ($response['errcode'] == 0) {
            return $response['result']['userid'];
        } else {
            return $response['errmsg'];
        }
    }

    /**
     * 注册服务
     *
     * @return mixed
     */
    public function register()
    {
        //
    }

    /**
     * 执行服务
     *
     * @return mixed
     */
    public function boot()
    {
        //
    }
}
